package com.dwms.interceptor;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.dwms.cache.DictCache;
import com.dwms.cache.LoginCache;
import com.dwms.constant.HeaderConstants;
import com.dwms.entity.Result;
import com.dwms.entity.UserLoginVO;
import com.dwms.enums.ResultCode;
import com.dwms.utils.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

@Slf4j
@Component
public class AdminInterceptor implements HandlerInterceptor {

    public static String active;

    @Value("${spring.profiles.active}")
    public void setActive(String active) {
        AdminInterceptor.active = active;
    }

    private boolean getActive() {
        return "dev".equals(active);
    }

    /**
     * 忽略认证URL
     */
    private static final String[] IGNORE_AUTH_URL = {
            "/auth/findRouters",
            "/auth/getUserInfo",
            "/auth/getSetting",
            "/system/cache/flushCache",
            "/findList",
            "/findTree",
            "/findByKeywords",
            "/upload",
            "/plugin",
            "/findByRelationId",
            "/file",
            "/product/importExcel",
            "/declare/jeInbound/importExcel",
            "/declare/jeOutbound/importExcel",
            "/plat/order/importHsReceipt"
    };

    /**
     * 忽略请求URL
     */
    private final static String[] IGNORE_REQUEST_URL = {
            "/auth/login",
            "/auth/getVerifyCode",
            "/auth/getPublicKey",
            "/auth/logout",
    };

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //解决跨域
        response.setHeader("Access-Control-Allow-Origin", "*");
        String requestUri = request.getRequestURI();
        long startTime = System.currentTimeMillis();
        request.setAttribute("startTime", startTime);
        log.info("运营端，请求request信息requestUri:" + requestUri);
        String loginToken = request.getHeader(HeaderConstants.LOGIN_TOKEN);
        String sign = request.getHeader(HeaderConstants.SIGN);
        String source = request.getHeader(HeaderConstants.SOURCE);
        String referer = request.getHeader(HeaderConstants.REFERER);
        boolean okKey = SignUtil.COMMON_SIGN_KEY.equals(sign);

        //直接放过的请求
        if ((StrUtil.isNotEmpty(referer) && referer.contains("swagger"))) {
            return true;
        }

        //直接放过的请求
        for (String reqURI : IGNORE_REQUEST_URL) {
            if (requestUri.contains(reqURI)) {
                return true;
            }
        }

        if (!okKey && !getActive() && !RedisUtils.setnx(sign) && !ArrayUtils.contains(IGNORE_AUTH_URL, requestUri)) {
            WebUtil.outPrint(response, JSON.toJSONString(Result.failed(ResultCode.ACCESS_UNAUTHORIZED)));
            return false;
        }
        Result result = SignUtil.checkSign(IGNORE_AUTH_URL, requestUri, request);
        if (result.isFailed()) {
            WebUtil.outPrint(response, JSON.toJSONString(Result.failed(result.getMessage())));
            return false;
        }

        if (EmptyUtils.isEmpty(loginToken)) {
            WebUtil.outPrint(response, JSON.toJSONString(Result.failed(ResultCode.TOKEN_IS_BLANK)));
            return false;
        }
        UserLoginVO userLoginVO = LoginCache.getUserLoginVO(loginToken);
        if (userLoginVO != null) {
            //判断是否是黑名单
            List<String> blackList = DictCache.getBlackList();
            if (!blackList.isEmpty() && blackList.contains(userLoginVO.getAccount())) {
                WebUtil.outPrint(response, JSON.toJSONString(Result.failed(ResultCode.BLACK_LIST)));
                return false;
            }
            List<String> permissions = LoginCache.getPermissions(loginToken);
            permissions.addAll(CommonUtils.arrayToListStr(IGNORE_AUTH_URL));
            if (permissions.stream().filter(Objects::nonNull).anyMatch(requestUri::contains)) {
                LoginCache.expireUserLoginTime(loginToken);
                return true;
            }
//            if (ArrayUtils.contains(permissions.toArray(), requestUri)) {
//                LoginCache.expireUserLoginTime(loginToken);
//                return true;
//            }
            WebUtil.outPrint(response, JSON.toJSONString(Result.failed(ResultCode.ACCESS_UNAUTHORIZED)));
            return false;
        }
        WebUtil.outPrint(response, JSON.toJSONString(Result.failed(ResultCode.TOKEN_INVALID)));
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        long startTime = (Long) request.getAttribute("startTime");
        long endTime = System.currentTimeMillis();
        long consumeTime = endTime - startTime;
        log.info("postHandle-response.getStatus()：" + response.getStatus());
        log.info("postHandle访问目标:" + method.getDeclaringClass().getName() + "." + method.getName() + "，消耗时间：" + consumeTime + " ms");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        log.info("afterCompletion-response.getStatus()：" + response.getStatus());
        log.info("afterCompletion-getShortLogMessage：" + handlerMethod.getShortLogMessage());
        log.info("afterCompletion-访问目标：" + method.getDeclaringClass().getName() + "." + method.getName() + " 结束");
    }
}
